package ddz.utils;

import ch.qos.logback.classic.Logger;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.PrettyPrinter;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

/**
 * {@link com.fasterxml.jackson.annotation.JsonProperty}
 * <p>为属性取别名的注解</p>
 * {@link com.fasterxml.jackson.annotation.JsonIgnore}
 * <p>忽略方法</p>
 * {@link JsonAutoDetect}
 * <p>类名注解，配合JsonProperty注解使用忽略方法</p>
 */
public class JsonUtils {

    private static Logger logger = (Logger) LoggerFactory.getLogger(JsonUtils.class);

    /**
     * 线程安全，可以全局使用
     */
    private static final ObjectMapper mapper = new ObjectMapper();

    static {
        SerializationConfig config = mapper.getSerializationConfig();
        //美化json输出的设置
        PrettyPrinter prettyPrinter = config.getDefaultPrettyPrinter();
        DefaultPrettyPrinter defpp = (DefaultPrettyPrinter) prettyPrinter;
        DefaultPrettyPrinter.Indenter indenter = new DefaultIndenter("\t", "\n");
        defpp.indentArraysWith(indenter);
        defpp.indentObjectsWith(indenter);


        // 允许出现特殊字符和转义符
        // mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        // 允许出现单引号
        // mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);

        // 字段保留，将null值转为""
//        mapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>()
//        {
//            @Override
//            public void serialize(Object o, JsonGenerator jsonGenerator,
//                                  SerializerProvider serializerProvider)
//                    throws IOException
//            {
//                jsonGenerator.writeString("");
//            }
//        });

//        try {
//
//        } catch (JsonMappingException e) {
//            e.printStackTrace();
//        }

        //将long数据全部转换为字符串
        //SimpleModule simpleModule = new SimpleModule();
        //simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        //simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        //mapper.registerModule(simpleModule);

        mapper.writer(defpp);
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        mapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        mapper.setLocale(Locale.CHINA);

        //仅关注字段，忽略get/set/is方法
        mapper.setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE);
        mapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);
        mapper.setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE);
        mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);

        // 通过该方法对mapper对象进行设置，所有序列化的对象都将按改规则进行系列化
        // Include.Include.ALWAYS 默认
        // Include.NON_DEFAULT 属性为默认值不序列化
        // Include.NON_EMPTY 属性为 空（""） 或者为 NULL 都不序列化，则返回的json是没有这个字段的。这样对移动端会更省流量
        // Include.NON_NULL 属性为NULL 不序列化
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        //mapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);
        // 将属性字段全部转为小写
        // mapper.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CASE);
    }

    /**
     * 将java对象转换为json对象
     *
     * @param javaObject java对象
     * @param <T>        json对象的限定类型
     * @return json对象
     */
    public final static <T extends JsonNode> T toJsonObject(Object javaObject) {
        if (javaObject instanceof JsonNode) {
            return (T) javaObject;
        }
        //return mapper.convertValue(javaBean, JsonNode.class);
        JsonNode jsonObject = mapper.valueToTree(javaObject);
        return (T) jsonObject;
    }

    /**
     * 判断字符串是否为一个有效的json格式
     *
     * @param jsonInString
     * @return
     */
    public final static boolean isValidJson(String jsonInString) {
        try {
            mapper.readTree(jsonInString);
            return true;
        } catch (IOException e) {
            logger.error(e.getLocalizedMessage(), e);
        }
        return false;
    }

    /**
     * 创建一个空的JsonObject对象
     *
     * @return
     */
    public final static ObjectNode createJsonObject() {
        return mapper.createObjectNode();
    }

    /**
     * 创建一个空的JsonArray对象
     *
     * @return
     */
    public final static ArrayNode createJsonArray() {
        return mapper.createArrayNode();
    }

    /**
     * 将java对象转换为json字符串
     *
     * @param value
     * @return
     */
    public final static String toJsonString(Object value) {
        try {
            return mapper.writeValueAsString(value);
        } catch (JsonProcessingException e) {
            logger.error(e.getLocalizedMessage(), e);
        }
        return null;
    }

    /**
     * 美化json输出
     *
     * @param value
     * @return
     */
    public final static String toPrettyJsonString(Object value) {
        try {
            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(value);
        } catch (JsonProcessingException e) {
            logger.error(e.getLocalizedMessage(), e);
        }
        return null;
    }

    /**
     * 将json字符串转换为json对象
     *
     * @param json
     * @param <T>
     * @return
     */
    public final static <T extends JsonNode> T toJsonNode(String json) {
        if (json == null || "".equals(json)) return null;
        try {
            return (T) mapper.readTree(json);
        } catch (IOException e) {
            logger.error(e.getLocalizedMessage(), e);
        }
        return null;
    }

    /**
     * 获取集合类型描述
     *
     * @param collectionClass 集合类型
     * @param elementClasses  集合的元素类型
     * @return 类型描述
     */
    public final static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
        return mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }

    /**
     * 将json字符串转换为java集合
     *
     * @param json            json字符串
     * @param collectionClass 集合类型
     * @param elementClasses  集合的元素类型
     * @param <T>             转换后的集合限定类型
     * @return 集合对象
     */
    public final static <T> Collection<T> toCollection(String json, Class<?> collectionClass, Class<T> elementClasses) {
        JavaType javaType = getCollectionType(collectionClass, elementClasses);
        try {
            return (Collection<T>) mapper.readValue(json, javaType);
        } catch (IOException e) {
            logger.error(e.getLocalizedMessage(), e);
        }
        return null;
    }

    /**
     * 将json字符串转换为Map键值对
     *
     * @param json       json字符串
     * @param mapClass   Map键值对Class
     * @param keyClass   键类型
     * @param valueClass 值类型
     * @param <K>        键类型限定
     * @param <V>        值类型限定
     * @return Map键值对
     */
    public final static <K, V> Map<K, V> toMap(String json, Class<? extends Map> mapClass, Class<K> keyClass, Class<V> valueClass) {
        JavaType javaType = mapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass);
        try {
            return mapper.readValue(json, javaType);
        } catch (IOException e) {
            logger.error(e.getLocalizedMessage(), e);
        }
        return null;
    }

    /**
     * 将json字符串转换为java对象
     *
     * @param json
     * @param type
     * @param <T>
     * @return
     */
    public final static <T> T parseObject(String json, Class<T> type) {
        try {
            return mapper.readValue(json, type);
        } catch (IOException e) {
            logger.error(e.getLocalizedMessage(), e);
        }
        return null;
    }

    /**
     * 将json字符串转换为java对象
     *
     * @param json           json字符串
     * @param type           目标对象类型
     * @param elementClasses 如果目标对象类型为集合，则此参数表示集合的元素类型
     * @return 对象
     */
    public final static Object parseObject(String json, Class<?> type, Class<?>... elementClasses) {
        try {
            if (elementClasses.length > 0) {
                JavaType javaType = getCollectionType(type, elementClasses);
                return mapper.readValue(json, javaType);
            }
            return mapper.readValue(json, type);
        } catch (IOException e) {
            logger.error(e.getLocalizedMessage(), e);
        }
        return null;
    }

}
